package bma.common.langutil.jmshell.command;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import bma.common.langutil.core.StringUtil;
import bma.common.langutil.jmshell.JMShellProcessor;
import bma.common.langutil.jmshell.JMShellUtil;
import bma.common.langutil.jmshell.Session;
import bma.common.langutil.jmshell.cmdopt.CommandOptionParser;

public class JMShellModule implements JMShellProcessor, CommandSet {

	protected class ModuleCommand extends AbstractSimpleCommandProcessor {
		public ModuleCommand() {
			super("module");
			setArgsTips("[activeModuleName|none]");
		}

		@Override
		public CommandOptionParser createCommandOption(Session session) {
			CommandOptionParser r = new CommandOptionParser();
			r.addBooleanOption('l', "list", "list all modules");
			return r;
		}

		@Override
		public boolean processCommand(Session session, String cmd,
				CommandOptionParser options) {
			if (options.getOptionValue("list", Boolean.FALSE)) {
				listModules(session);
				return true;
			}
			String[] remains = options.getRemainingArgs();
			if (remains != null && remains.length > 0) {
				setActive(session, remains[0]);
			} else {
				displayActive(session);
			}
			return true;
		}

		private void displayActive(Session session) {
			StringBuilder sb = new StringBuilder();
			sb.append("active module: ");
			ActiveInfo info = JMShellUtil.getData(session, DATA_KEY,
					ActiveInfo.class, false);
			String activeModule = info == null ? null : info.activeModule;
			if (activeModule != null) {
				sb.append(activeModule);
			} else {
				sb.append("none");
			}
			session.writeln(sb.toString());
		}

		private void setActive(Session session, String name) {
			JMShellProcessor p = null;
			String pname = name;
			if (StringUtil.equals(name, "none")) {
				p = null;
				pname = null;
			} else {
				if (processors != null) {
					p = processors.get(name);
				}
				if (p == null) {
					session.writeln("ERROR: unknow '" + name + "' module");
					return;
				}
			}
			synchronized (this) {
				ActiveInfo info = JMShellUtil.getData(session, DATA_KEY,
						ActiveInfo.class, true);
				info.activeProcessor = p;
				info.activeModule = pname;
			}
			session.writeln("active module => " + name);
		}

		private void listModules(Session session) {
			StringBuilder sb = new StringBuilder();
			sb.append("modules: ");
			if (processors != null) {
				Iterator<String> it = processors.keySet().iterator();
				while (it.hasNext()) {
					String name = it.next();
					sb.append(name);
					if (it.hasNext())
						sb.append(",");
				}
			}
			session.writeln(sb.toString());
		}

	}

	public static class ActiveInfo {
		protected String activeModule;
		protected JMShellProcessor activeProcessor;
	}

	public static final String DATA_KEY = "@module_active";

	protected JMShellProcessor moduleCommand = new ModuleCommand();
	protected Map<String, JMShellProcessor> processors;

	public Map<String, JMShellProcessor> getProcessors() {
		return processors;
	}

	public void setProcessors(Map<String, JMShellProcessor> processors) {
		this.processors = processors;
	}

	public void addProcessor(String name, JMShellProcessor p) {
		if (this.processors == null) {
			this.processors = new HashMap<String, JMShellProcessor>();
		}
		this.processors.put(name, p);
	}

	@Override
	public boolean process(Session session, String command) {
		if (moduleCommand.process(session, command)) {
			return true;
		}
		ActiveInfo info = JMShellUtil.getData(session, DATA_KEY,
				ActiveInfo.class, false);
		JMShellProcessor p = info == null ? null : info.activeProcessor;
		if (p != null) {
			return p.process(session, command);
		}
		return false;
	}

	@Override
	public void listCommands(Session session, List<String> results) {
		JMShellUtil.handleListCommand(session, results, moduleCommand);
		ActiveInfo info = JMShellUtil.getData(session, DATA_KEY,
				ActiveInfo.class, false);
		JMShellProcessor p = info == null ? null : info.activeProcessor;
		if (p != null) {
			JMShellUtil.handleListCommand(session, results, p);
		}
	}
}
